use std::{fs, path::Path};

use crate::{parse, ALL_STRUCT};

pub fn generate(parse_struct: &parse::Struct)
{
    let generate_file_dir = format!(
        "{}/target/ser/cs",
        std::env::current_dir().expect("AAA").to_str().expect("BBB")
    );
    let cs_file_path = format!(
        "{}/{}",
        generate_file_dir,
        parse_struct.file_name.replace(".rs", ".cs")
    );

    unsafe {
        if ALL_STRUCT.len() == 0
        {
            if Path::new(&generate_file_dir).exists()
            {
                fs::remove_dir_all(&generate_file_dir).expect("删除target/ser/cs文件夹出错！");
            }
            fs::create_dir_all(&generate_file_dir).expect("创建target/ser/cs文件夹出错！");
        }
        let mut ss = Vec::<&parse::Struct>::new();
        ss.push(parse_struct);
        for v in &ALL_STRUCT
        {
            if v.file_name == parse_struct.file_name
            {
                ss.push(&v);
            }
        }
        ss.sort_by_key(|k| k.line);
        let mut file_str = "using System;\n".to_string();
        for s in &ss
        {
            file_str += &(to_string(s) + "\n");
        }
        fs::write(Path::new(&cs_file_path), file_str)
            .expect(format!("写入{}文件出错！", cs_file_path).as_str());
    }
}

fn to_string(parse_struct: &parse::Struct) -> String
{
    let mut annotation = String::new();
    if parse_struct.annotation.len() > 0
    {
        annotation = "\n/// <summary>".to_string();
        for a in &parse_struct.annotation
        {
            annotation += &format!("\n///{}", a);
        }
        annotation += "\n/// </summary>";
    }
    let mut body = String::new();
    for v in &parse_struct.fields
    {
        //生成注释
        if v.annotation.len() > 0
        {
            body += "\n    /// <summary>";
            for a in &v.annotation
            {
                body += &format!("\n    ///{}", a);
            }
            body += "\n    /// </summary>";
        }
        //生成字段
        match &v.field_type
        {
            parse::Type::I8 => body += &format!("\n    public sbyte {};", v.field_name),
            parse::Type::I16 => body += &format!("\n    public short {};", v.field_name),
            parse::Type::I32 => body += &format!("\n    public int {};", v.field_name),
            parse::Type::I64 => body += &format!("\n    public long {};", v.field_name),
            parse::Type::U8 => body += &format!("\n    public byte {};", v.field_name),
            parse::Type::U16 => body += &format!("\n    public ushort {};", v.field_name),
            parse::Type::U32 => body += &format!("\n    public uint {};", v.field_name),
            parse::Type::U64 => body += &format!("\n    public ulong {};", v.field_name),
            parse::Type::F32 => body += &format!("\n    public float {};", v.field_name),
            parse::Type::F64 => body += &format!("\n    public double {};", v.field_name),
            parse::Type::Bool => body += &format!("\n    public bool {};", v.field_name),
            parse::Type::String => body += &format!("\n    public string {};", v.field_name),
            parse::Type::Struct(sn) => body += &format!("\n    public {} {};", sn, v.field_name),
            parse::Type::Box(t) =>
            {
                //...
                match t.as_ref()
                {
                    parse::Type::I8 => body += &format!("\n    public sbyte {};", v.field_name),
                    parse::Type::I16 => body += &format!("\n    public short {};", v.field_name),
                    parse::Type::I32 => body += &format!("\n    public int {};", v.field_name),
                    parse::Type::I64 => body += &format!("\n    public long {};", v.field_name),
                    parse::Type::U8 => body += &format!("\n    public byte {};", v.field_name),
                    parse::Type::U16 => body += &format!("\n    public ushort {};", v.field_name),
                    parse::Type::U32 => body += &format!("\n    public uint {};", v.field_name),
                    parse::Type::U64 => body += &format!("\n    public ulong {};", v.field_name),
                    parse::Type::F32 => body += &format!("\n    public float {};", v.field_name),
                    parse::Type::F64 => body += &format!("\n    public double {};", v.field_name),
                    parse::Type::Bool => body += &format!("\n    public bool {};", v.field_name),
                    parse::Type::String =>
                    {
                        body += &format!("\n    public string {};", v.field_name)
                    }
                    parse::Type::Struct(sn) =>
                    {
                        body += &format!("\n    public {} {};", sn, v.field_name)
                    }
                    _ => println!(""),
                }
            }
            parse::Type::Vec(t) =>
            {
                //...
                match t.as_ref()
                {
                    parse::Type::I8 => body += &format!("\n    public sbyte[] {};", v.field_name),
                    parse::Type::I16 => body += &format!("\n    public short[] {};", v.field_name),
                    parse::Type::I32 => body += &format!("\n    public int[] {};", v.field_name),
                    parse::Type::I64 => body += &format!("\n    public long[] {};", v.field_name),
                    parse::Type::U8 => body += &format!("\n    public byte[] {};", v.field_name),
                    parse::Type::U16 => body += &format!("\n    public ushort[] {};", v.field_name),
                    parse::Type::U32 => body += &format!("\n    public uint[] {};", v.field_name),
                    parse::Type::U64 => body += &format!("\n    public ulong[] {};", v.field_name),
                    parse::Type::F32 => body += &format!("\n    public float[] {};", v.field_name),
                    parse::Type::F64 => body += &format!("\n    public double[] {};", v.field_name),
                    parse::Type::Bool => body += &format!("\n    public bool[] {};", v.field_name),
                    parse::Type::String =>
                    {
                        body += &format!("\n    public string[] {};", v.field_name)
                    }
                    parse::Type::Struct(sn) =>
                    {
                        body += &format!("\n    public {}[] {};", sn, v.field_name)
                    }
                    _ => println!(""),
                }
            }
            parse::Type::Array(t) =>
            {
                //...
                match t.as_ref()
                {
                    parse::Type::I8 => body += &format!("\n    public sbyte[] {};", v.field_name),
                    parse::Type::I16 => body += &format!("\n    public short[] {};", v.field_name),
                    parse::Type::I32 => body += &format!("\n    public int[] {};", v.field_name),
                    parse::Type::I64 => body += &format!("\n    public long[] {};", v.field_name),
                    parse::Type::U8 => body += &format!("\n    public byte[] {};", v.field_name),
                    parse::Type::U16 => body += &format!("\n    public ushort[] {};", v.field_name),
                    parse::Type::U32 => body += &format!("\n    public uint[] {};", v.field_name),
                    parse::Type::U64 => body += &format!("\n    public ulong[] {};", v.field_name),
                    parse::Type::F32 => body += &format!("\n    public float[] {};", v.field_name),
                    parse::Type::F64 => body += &format!("\n    public double[] {};", v.field_name),
                    parse::Type::Bool => body += &format!("\n    public bool[] {};", v.field_name),
                    parse::Type::String =>
                    {
                        body += &format!("\n    public string[] {};", v.field_name)
                    }
                    parse::Type::Struct(sn) =>
                    {
                        body += &format!("\n    public {}[] {};", sn, v.field_name)
                    }
                    _ => println!(""),
                }
            }
            _ => println!(""),
        }
    }
    format!(
        "{}\npublic class {}\n{{{}\n}}",
        annotation, parse_struct.struct_name, body
    )
}
